package typejump.util;

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;

/**
 * This is a class which allows convenient iteration over objects contained
 * in multiple lists.
 * @author g
 *
 * @param <T>
 */
public class NestedList<T> implements Iterable<T> {

	private LinkedList<Rit> istack = new LinkedList<Rit>();
	private ArrayList<List<T>> lists = new ArrayList<List<T>>();
	
	private final Object lock = new Object();

	
	public void add(List<T> list) {
		synchronized (lock) {
			this.lists.add(list);
		}
	}
	
	@Override
	public Iterator<T> iterator() {
		synchronized (lock) {
		if (istack.size() > 0) {
			Rit r = istack.pop();
			r.enable();
			return r;
		}
		}
		
		return new Rit();
	}
	
	private class Rit implements Iterator<T> {
		private int index = 0;
		private int clist = 0;
		private boolean enabled = true;
		private T next = null;
		
		public Rit() {
			enable();
		}
		
		public void enable() {
			this.enabled = true;
			this.index = 0;
			this.clist = 0;
			next = getCurrent();
		}
		
		private T getCurrent() {
			T n = null;
			while (n == null) {
				if (clist >= lists.size())
					return null;
				if (index < lists.get(clist).size()) {
					return lists.get(clist).get(index);
				} else {
					clist++;
					index = 0;
				}
			}
			return null; // This should never be reached
		}
		
		@Override
		public boolean hasNext() {
			return next != null;
		}

		@Override
		public T next() {
			if (!enabled) return null;
			
			if (hasNext()) {
				T t = next;
				index++;
				next = getCurrent();
				return t;
			}
			
			next = null;
			enabled = false;
			istack.add(this);
			return null;
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException("Remove not supported!");
		}
	}
}
